/**
 * Logging panel by Jared Brayshaw
 * 
 * Created for Task # on FogBugz:
 * https://msoe.fogbugz.com/default.asp?###
 */
package hydrap2p.gui;

import hydrap2p.gui.commands.Cmd_SearchPanel_AddResultToDownloadQueue;
import hydrap2p.gui.commands.Cmd_SearchPanel_StopSearch;
import hydrap2p.gui.commands.Cmd_SearchPanel_SubmitSearch;
import hydrap2p.gui.commands.CommandInvoker;
import hydrap2p.helper.ServiceConnector;
import hydrap2p.search.SearchResult;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;

import org.apache.thrift.TException;

/**
 * A panel that presents a search interface for the user.
 * 
 * @author Jared
 */
public class SearchPanel extends JSplitPane implements ActionListener
{	
	//the results of the search
	private JTable results;
	//private SearchObject currentResults;
	private List<SearchResult> currentResults;
	
	//popup menu and listener
	private ActionListener contextListener = new MenuItemListener();
	private JPopupMenu contextMenu = new TablePopupMenu();
	
	//all the graphical components
	private static final JTabbedPane inputArea = new JTabbedPane(JTabbedPane.LEFT);		//where the user enters search terms
	private static final JPanel protocolArea = new JPanel();							//where the user determines which protocols to search for
	
	private static final JPanel basicSearch = new JPanel();								//an interface for a basic OR search 
	private static final JPanel advancedSearch = new JPanel();							//an interface for more advanced searches
	
	//the input and output panels
	private static final JSplitPane searchArea = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, inputArea, protocolArea);
	private static final JScrollPane resultsArea = new JScrollPane();
	
	private static JTextField basicField;	//OR search field appearing on the basic tab
	private static JTextField anyField;		//OR search field appearing on the advanced tab
	private static JTextField allField;		//AND search field appearing on the basic tab
	private static JTextField noneField;	//NOT search field appearing on the basic tab
	
	//private static JCheckBox httpCheckbox;			//HTTP checkbox
	//private static JCheckBox btCheckbox;			//BitTorrent checkbox
	//private static JCheckBox ftpCheckbox;			//FTP checkbox
	//private static JCheckBox jc3;			//UseNet checkbox
	
	private List<JCheckBox> searchers = new ArrayList<JCheckBox>();
	
	private JButton goButton;
	private JButton stopButton;
	
	private int searchID;
	
	//singleton stuff
	private static volatile SearchPanel instance;
	
	public static synchronized SearchPanel getInstance(){
		if(instance == null){
			synchronized (SearchPanel.class){
				if(instance == null){
					instance = new SearchPanel();
				}
			}
		}
		return instance;
	}
	//end of singleton stuff
	
	
	/**
	 * Creates the panel by putting the search input panel on the top half of a splitpane and
	 * the results table on the bottom half.  After setting up the components, the results table
	 * is refreshed to make sure it has the most recent data.
	 */
	private SearchPanel(){
		super(JSplitPane.VERTICAL_SPLIT, searchArea, resultsArea);
		
		init();
		
		setOneTouchExpandable(true);
		setDividerLocation(275);		//there's probably a better way to do this, like getting the dimensions of the parent component
		setDividerSize(3);
		
		refreshInternalDetails(null);
	}
	
	/**
	 * Initializes all the data for the panel
	 */
	private void init()
	{	
		searchArea.setDividerLocation(600);
		searchArea.setDividerSize(3);
		
		JLabel jl0 = new JLabel("Enter search terms:");
		JLabel jl1 = new JLabel("Any of these terms:");
		JLabel jl2 = new JLabel("All of these terms:");
		JLabel jl3 = new JLabel("None of these terms:");
		
		basicField = new JTextField();
			basicField.setMaximumSize(new Dimension(1500, 20));
		anyField = new JTextField();
			anyField.setMaximumSize(new Dimension(1500, 20));
		allField = new JTextField();
			allField.setMaximumSize(new Dimension(1500, 20));
		noneField = new JTextField();
			noneField.setMaximumSize(new Dimension(1500, 20));
			
		JButton clearButton = new JButton("Clear Fields");
			clearButton.setActionCommand("clear");
			clearButton.addActionListener(this);
		
		//set up the search panels
		basicSearch.add(jl0);
		basicSearch.add(basicField);
		basicSearch.setLayout(new BoxLayout(basicSearch, BoxLayout.PAGE_AXIS));
		
		advancedSearch.add(jl1);
		advancedSearch.add(anyField);
		advancedSearch.add(jl2);
		advancedSearch.add(allField);
		advancedSearch.add(jl3);
		advancedSearch.add(noneField);
		advancedSearch.add(clearButton);
		advancedSearch.setLayout(new BoxLayout(advancedSearch, BoxLayout.PAGE_AXIS));
		
		inputArea.addTab("Basic Search", basicSearch);
		inputArea.addTab("Advanced Search", advancedSearch);
		
		
		searchID = 0;
		currentResults = new ArrayList<SearchResult>();
		
		goButton = new JButton("GO");
		goButton.setActionCommand("search");
		goButton.addActionListener(this);
		goButton.setVisible(true);
		
		stopButton = new JButton("STOP");
		stopButton.setActionCommand("stop");
		stopButton.addActionListener(this);
		stopButton.setVisible(false);
		
		refreshPlugins();
	}
	
	/**
	 * Takes all the info in the search pane and packs it into a single object.
	 */
	public SearchObject compileInputs()
	{
		Scanner s;
		List<String> any = new ArrayList<String>();
		List<String> all = new ArrayList<String>();
		List<String> none = new ArrayList<String>();
		
		int currentTab = inputArea.getSelectedIndex();
		
		boolean basicTabIsSelected = (currentTab == 0);	//the basic tab is the first one
		
		if (basicTabIsSelected)
		{
			s = new Scanner(basicField.getText());
			while (s.hasNext())
				any.add(s.next());
			
			//the other lists should remain empty
		}
		else
		{
			//get the terms that might be in results
			s = new Scanner(anyField.getText());
			while (s.hasNext())
				any.add(s.next());
			
			//get the terms that must be in results
			s = new Scanner(allField.getText());
			while (s.hasNext())
				all.add(s.next());
			
			//get the terms to exclude
			s = new Scanner(noneField.getText());
			while (s.hasNext())
				none.add(s.next());
		}
		
		List<String> modulesToSearch = new ArrayList<String>();
		
		for (JCheckBox jcb : searchers)
		{
			if (jcb.isSelected())
				modulesToSearch.add(jcb.getText());
		}
		
		return new SearchObject(any, all, none, modulesToSearch);
	}
	
	public void refreshPlugins()
	{
		System.out.println("I AM HERE!");
		protocolArea.removeAll();
		protocolArea.setLayout(new BoxLayout(protocolArea, BoxLayout.PAGE_AXIS));
		
		//set up the protocol panel
		protocolArea.add(new JLabel("Search Plugins:"));
		
		//dynamically create the checkboxes for search modules
			
		if (ServiceConnector.getSearcher() != null)	//search manager is running
		{
			List<String> searchModules = new ArrayList<String>();
			
			try {
				searchModules = ServiceConnector.getSearcher().listSearchProviders();
			} catch (TException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			for (String s : searchModules)
			{
				JCheckBox chkBox = new JCheckBox(s);
				chkBox.setSelected(true);
				protocolArea.add(chkBox);
				searchers.add(chkBox);
			}
		}
		
		protocolArea.add(goButton);
		protocolArea.add(stopButton);
		
	}
	
	/**
	 * Updates the results table with the results of a search
	 * 
	 * @param searchResults		the results to fill the table with
	 */
	private void refreshInternalDetails(List<GUIDownloadListing> searchResults)
	{		
		//set up the table contents
		Vector<String> columnNames = new Vector<String>();
			columnNames.add("Name");
			columnNames.add("Protocol");
		Vector<Vector<String>> data = new Vector<Vector<String>>();
		
		//add the results, if there are any
		if (searchResults != null)
		{
			for (GUIDownloadListing gdl : searchResults)
			{
				if( /*(gdl.getProtocol().equals("HTTP") && !httpCheckbox.isSelected())
						|| (gdl.getProtocol().equals("FTP") && !ftpCheckbox.isSelected())
						|| (gdl.getProtocol().equals("BitTorrent") && !btCheckbox.isSelected()) */ false ){
					System.out.println("Result filtered");
				}else{
					Vector<String> v = new Vector<String>();
					v.add(gdl.getName());
					v.add(gdl.getProtocol());
					data.add(v);
				}
			}
		}
		
		results = new JTable(data, columnNames) { public boolean isCellEditable(int rowIndex, int vColIndex) { return false; }};
		results.addMouseListener(new PopupListener());
		
		/*
		//set up the columns
			//figure out how to set an initial position for the column divider (preferably without getting width info from the panel)
		TableColumn column;
        
		column = results.getColumnModel().getColumn(0);
        column.setMinWidth(75);
        
		column = results.getColumnModel().getColumn(1);
        column.setMinWidth(125);
        column.setWidth(125);
        */
		
		resultsArea.setViewportView(results);
	}
	
	public int getSearchID(){
		return searchID;
	}
	
	public void setSearchID(int sid){
		searchID = sid;
	}
	
	public void refreshDetails0(List<SearchResult> searchResults)
	{	
		//save the selection so we can restore it when we redraw the table
		int[] selectedRows = {};
		if (results != null)
		{
			selectedRows = results.getSelectedRows();
		}
		
		
		/*
		try {
			GUIDataHandler.getInstance().log(GUIDataHandler.LOG_DEBUG, "SearchPanel", "refreshing with " + selectedRows.length + " rows selected.");
		} catch (TException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//*/
		//set up the table contents
		Vector<String> columnNames = new Vector<String>();
			columnNames.add("Name");
			columnNames.add("Protocol");
		Vector<Vector<String>> data = new Vector<Vector<String>>();
		
		//add the results, if there are any
		if (searchResults != null)
		{
			for (SearchResult sr : searchResults)
			{
				Vector<String> v = new Vector<String>();
				v.add(sr.getNames().get(0));
				v.add(sr.getSources().get(0).getProtocol()); // TODO FIX THIS
				data.add(v);
			}
		}
		
		results = new JTable(data, columnNames) { public boolean isCellEditable(int rowIndex, int vColIndex) { return false; }};
		results.addMouseListener(new PopupListener());
		results.setAutoCreateRowSorter(true);
		
		//restore the selection
		for (int row : selectedRows)
		{
			results.addRowSelectionInterval(row, row);
		}
		
		/*
		//set up the columns
			//figure out how to set an initial position for the column divider (preferably without getting width info from the panel)
		TableColumn column;
        
		column = results.getColumnModel().getColumn(0);
        column.setMinWidth(75);
        
		column = results.getColumnModel().getColumn(1);
        column.setMinWidth(125);
        column.setWidth(125);
        */
		
		resultsArea.setViewportView(results);
	}//*/
	
	
	public JTable getTable(){
		return results;
	}
	
	private void setCheckBoxesEnabled(boolean val)
	{
		for (JCheckBox jcb : searchers)
		{
			jcb.setEnabled(val);
		}
	}
	
	public void searchIsFinished(){
		stopButton.setVisible(false);
		goButton.setVisible(true);
		setCheckBoxesEnabled(true);
	}
	
	public List<SearchResult> getCurrentResults(){
		return currentResults;
	}
	
	public void setCurrentResults(List<SearchResult> results){
		currentResults = results;
	}
	
	class MenuItemListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand() == "addToQueue")
			{
				CommandInvoker.getInstance().invokeCommand(new Cmd_SearchPanel_AddResultToDownloadQueue());
				//System.out.println("Added to Queue");
			}
		}
	}
	
	@Override
	public void actionPerformed(ActionEvent arg0) {
		if (arg0.getActionCommand() == "search")
		{
			CommandInvoker.getInstance().invokeCommand(new Cmd_SearchPanel_SubmitSearch());
			goButton.setVisible(false);
			stopButton.setVisible(true);
			setCheckBoxesEnabled(false);
			
		}
		else if (arg0.getActionCommand() == "stop")
		{
			CommandInvoker.getInstance().invokeCommand(new Cmd_SearchPanel_StopSearch());
			stopButton.setVisible(false);
			goButton.setVisible(true);
			setCheckBoxesEnabled(true);
			
		}
		else if (arg0.getActionCommand() == "clear")
		{
			anyField.setText("");
			allField.setText("");
			noneField.setText("");
			/*
			try {
				GUIDataHandler.getInstance().log(GUIDataHandler.LOG_INFO, "Search Panel", "Clear Performed");
			} catch (TException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//*/
		}
	}
	
	private class TablePopupMenu extends JPopupMenu {
        public TablePopupMenu() {
            super();
            addNewStringItem("Add to Queue", "addToQueue");
            
        }
        @Override
        public void show(Component c, int x, int y) {
            int[] l = results.getSelectedRows();
            super.show(c, x, y);
        }
        
        private void addNewStringItem(String name, String command)
        {
        	JMenuItem temp = new JMenuItem(name);
        	temp.addActionListener(contextListener);
        	temp.setActionCommand(command);
        	add(temp);
        }
    }
	
	class PopupListener extends MouseAdapter {
	    public void mousePressed(MouseEvent e) {
	        maybeShowPopup(e);
	    }

	    public void mouseReleased(MouseEvent e) {
	        maybeShowPopup(e);
	    }

	    private void maybeShowPopup(MouseEvent e) {
	        if (e.isPopupTrigger()) {
	        	contextMenu.show(e.getComponent(), e.getX(), e.getY());
	        }
	    }
	}
}
